home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Applications… / QuickDraw GX Aware Sample ƒ / Simple Sample GX ƒ / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-20  |  20.4 KB  |  771 lines  |  [TEXT/MMCC]

  1. /*********************************************************************
  2.  
  3.     files.c
  4.     
  5.     This file contains the file I/O code for the QuickDraw GX aware
  6.     sample, "Simple Sample GX."
  7.     
  8.     Additional info can be found in the related develop #19 article,
  9.     "Adding QuickDraw GX Printing to QuickDraw Applications."
  10.  
  11.     Dave Hersey, Apple Developer Technical Support.
  12.     
  13.     ——————— Edit Trail ———————
  14.     
  15.     hatched:                                        1/22/94  - dmh
  16.     cleaned up for 2nd draft of develop article:    3/10/94  - dmh
  17.     cleaned up for final:                            4/14/94  - dmh
  18.     universalized:                                    8/25/94  - dmh
  19.     
  20. *********************************************************************/
  21.  
  22. #include "Simple Sample.h"
  23.  
  24.  
  25. /************************************************************
  26.   MyLoadDocument - This routine loads a previously saved
  27.   document.
  28.  
  29. *************************************************************/
  30.  
  31. OSErr MyLoadDocument(MyDocumentPtr whichDocument)
  32. {
  33.     OSErr                err;
  34.     short                oldResFile, dataRefNum = -1, resRefNum = -1;
  35.     StandardFileReply    sfReply;
  36.     SFTypeList            myTypeList;
  37.  
  38. // Let the user select a document to open.
  39.  
  40.     myTypeList[0] = kMyDocType;
  41.     StandardGetFile(nil, 1, myTypeList, &sfReply);
  42.     require_action(sfReply.sfGood, UserHasCancelled, err = iPrAbort;);
  43.  
  44. /*
  45.     Make sure that we haven't already opened this document. If
  46.     we have, just bring the old window forward.
  47. */
  48.     nrequire_action(MyIsWindowAlreadyOpen(&sfReply.sfFile),
  49.                     DocIsAlreadyOpen, err = iPrAbort;);
  50.  
  51. // Open the selected file's data fork and resource fork.
  52.  
  53.     err = FSpOpenDF(&sfReply.sfFile, fsRdWrPerm, &dataRefNum);
  54.     nrequire(err, CouldNotOpenDataFork);
  55.  
  56.     resRefNum = HOpenResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  57.                              sfReply.sfFile.name, fsRdPerm);
  58.  
  59.     err = ResError();
  60.     nrequire(err, CouldNotOpenResourceFork);
  61.  
  62. /*
  63.     If we're successful in opening the file, set our document's
  64.     FSSpec info, its title, and its window's title.
  65. */
  66.  
  67.     oldResFile = CurResFile();
  68.     
  69.     BlockMove(&sfReply.sfFile, &whichDocument->documentFSSpec, sizeof(FSSpec));
  70.     BlockMove(&sfReply.sfFile.name, whichDocument->documentTitle,
  71.               (long) sfReply.sfFile.name[0] +1);
  72.     
  73.     SetWTitle(whichDocument->documentWindow, whichDocument->documentTitle);
  74.     err = MyLoadPrintInfo(whichDocument, resRefNum);
  75.  
  76. // Now load the data for our document's pages.
  77.  
  78.     whichDocument->numPages = MyLoadPageCount(resRefNum);
  79.     whichDocument->curPage = 1;
  80.  
  81.     /* 
  82.         Place your application-specific code here to load 
  83.         other data associated with the document.
  84.         .
  85.         .
  86.         .
  87.     */
  88.  
  89.     MyAdjustMenus();
  90.  
  91. // Close the data and resource forks of this document.
  92.  
  93.     UseResFile(oldResFile);
  94.     CloseResFile(resRefNum);
  95.  
  96. CouldNotOpenResourceFork:
  97.     FSClose(dataRefNum);
  98.  
  99. CouldNotOpenDataFork:
  100. DocIsAlreadyOpen:
  101. UserHasCancelled:
  102.     return err;
  103. }
  104.  
  105.  
  106. /************************************************************
  107.   MyFSLoadDocument - This routine opens a document and loads
  108.   its previously saved job, reassociating any formats that
  109.   the job contains.  It's just like MyLoadDocument, but it
  110.   opens the indicated file and doesn't present a file
  111.   dialog.
  112.  
  113. *************************************************************/
  114.  
  115. OSErr MyFSLoadDocument(MyDocumentPtr whichDocument, FSSpec *docFSSpec,
  116.                        Boolean forPrinting)
  117. {
  118.     OSErr        err;
  119.     short        oldResFile, dataRefNum, resRefNum;
  120.  
  121. /*
  122.     Unless we're printing, make sure that we haven't already opened
  123.     this document. If we have, just bring the old window forward.
  124. */
  125.  
  126.     require_action(forPrinting || !MyIsWindowAlreadyOpen(docFSSpec),
  127.                    DocIsAlreadyOpen, err = iPrAbort;);
  128.  
  129. // Open the selected file's data fork and resource fork.
  130.  
  131.     err = FSpOpenDF(docFSSpec, fsRdWrPerm, &dataRefNum);
  132.     nrequire(err, CouldNotOpenDataFork);
  133.  
  134.     resRefNum = HOpenResFile(docFSSpec->vRefNum, docFSSpec->parID, docFSSpec->name, fsRdPerm);
  135.     err = ResError();
  136.     nrequire(err, CouldNotOpenResourceFork);
  137.  
  138. /*
  139.     If we're successful in opening the file, set our document's
  140.     FSSpec info and its window's title.
  141. */
  142.  
  143.     oldResFile = CurResFile();
  144.  
  145.     BlockMove(docFSSpec, &whichDocument->documentFSSpec, sizeof(FSSpec));
  146.     BlockMove(docFSSpec->name, whichDocument->documentTitle, (long) docFSSpec->name[0] +1);
  147.     SetWTitle(whichDocument->documentWindow, whichDocument->documentTitle);
  148.  
  149.     err = MyLoadPrintInfo(whichDocument, resRefNum);
  150.  
  151. // Now load the data for our document's pages.
  152.  
  153.     whichDocument->numPages = MyLoadPageCount(resRefNum);
  154.     whichDocument->curPage = 1;
  155.  
  156.     /* 
  157.         Place your application-specific code here to load 
  158.         other data associated with the document.
  159.         .
  160.         .
  161.         .
  162.     */
  163.  
  164.     MyAdjustMenus();
  165.  
  166. // Close the data and resource forks of this document.
  167.  
  168.     UseResFile(oldResFile);
  169.     CloseResFile(resRefNum);
  170.  
  171. CouldNotOpenResourceFork:
  172.     FSClose(dataRefNum);
  173.  
  174. CouldNotOpenDataFork:
  175. DocIsAlreadyOpen:
  176.     return err;
  177. }
  178.  
  179.  
  180. /************************************************************
  181.   MyIsWindowAlreadyOpen - This routine compares a file spec
  182.   with those for our currently opened documents.  If we find
  183.   a match, we bring that document's window forward and return
  184.   true.  Otherwise, we return false.
  185.  
  186. *************************************************************/
  187.  
  188. Boolean MyIsWindowAlreadyOpen(FSSpec *whichFSSpec)
  189. {
  190.     WindowPtr        curWindow;
  191.     MyDocumentPtr    curDocument;
  192.     Boolean            isAlreadyOpen = false;
  193.  
  194. /*
  195.     Make sure that we haven't already opened this document. If
  196.     we have, just bring the old window forward and adjust our menus.
  197. */
  198.     curWindow = FrontWindow();
  199.     
  200.     while (curWindow != nil)
  201.     {
  202.         if (((WindowPeek) curWindow)->windowKind == userKind)
  203.         {
  204.             curDocument = MyGetDocPtr(curWindow);
  205.             
  206.             isAlreadyOpen =
  207.                 ((curDocument->documentFSSpec.vRefNum == whichFSSpec->vRefNum) &&
  208.                  (curDocument->documentFSSpec.parID == whichFSSpec->parID) &&
  209.                  (IUEqualString(curDocument->documentFSSpec.name, whichFSSpec->name) == 0));
  210.  
  211.             if (isAlreadyOpen)
  212.             {
  213.                 SelectWindow(curWindow);
  214.                 MyAdjustMenus();
  215.             }
  216.             
  217.             nrequire(isAlreadyOpen, DocIsAlreadyOpen);
  218.         }
  219.     
  220.         curWindow = (WindowPtr) ((WindowPeek) curWindow)->nextWindow;
  221.     }
  222.  
  223. DocIsAlreadyOpen:
  224. NoNeedToCheck:
  225.     return isAlreadyOpen;
  226. }
  227.  
  228.  
  229. /************************************************************
  230.   MySaveDocument - This routine saves a document and its
  231.   corresponding job to disk.  It also saves a format
  232.   collection item containing our page-to-format
  233.   correpondences.
  234.  
  235. *************************************************************/
  236.  
  237. OSErr MySaveDocument(MyDocumentPtr whichDocument, Boolean doingSaveAs)
  238. {
  239.     OSErr                err = noErr;
  240.     short                dataRefNum, oldResFile, resRefNum;
  241.     FSSpec                *docFSSpec;
  242.     StandardFileReply    sfReply;
  243.     FInfo                docFInfo;
  244.  
  245.     oldResFile = CurResFile();
  246.     docFSSpec = &whichDocument->documentFSSpec;
  247.  
  248. /*
  249.     If we're doing a "Save as…", display the StandardFile
  250.     dialog and have the user select a place to save the file.
  251. */
  252.  
  253.     if (doingSaveAs)
  254.     {
  255.         StandardPutFile("\pSave document:", whichDocument->documentTitle, &sfReply);
  256.         require(sfReply.sfGood, UserHasCancelled);
  257.  
  258. /*
  259.     If we're replacing an existing file, delete it.  Create
  260.     our new file and set its creator and type.
  261. */
  262.         if (sfReply.sfReplacing)
  263.             err = HDelete(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  264.  
  265.         nrequire(err, CouldNotDeleteOldFile);
  266.  
  267.         HCreateResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  268.         HGetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  269.                   sfReply.sfFile.name, &docFInfo);
  270.               
  271.         docFInfo.fdCreator = kMyDocCreator;
  272.         docFInfo.fdType = kMyDocType;
  273.  
  274.         err = HSetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  275.                         sfReply.sfFile.name, &docFInfo);
  276.  
  277. /*
  278.     If we're successful in creating the file, set our document's
  279.     FSSpec info, its title and its window's title.
  280. */
  281.  
  282.         if (err == noErr) err = ResError();
  283.         nrequire(err, CouldNotSetFileInfo);
  284.  
  285.         BlockMove(&sfReply.sfFile, docFSSpec, sizeof(FSSpec));
  286.         BlockMove(&sfReply.sfFile.name, whichDocument->documentTitle,
  287.                   (long) sfReply.sfFile.name[0] +1);
  288.         
  289.         SetWTitle(whichDocument->documentWindow, whichDocument->documentTitle);
  290.     }
  291.  
  292. // Open the file's data fork and resource fork.
  293.  
  294.     err = FSpOpenDF(docFSSpec, fsRdWrPerm, &dataRefNum);
  295.     nrequire(err, CouldNotOpenDataFork);
  296.  
  297.     resRefNum = HOpenResFile(docFSSpec->vRefNum, docFSSpec->parID,
  298.                              docFSSpec->name, fsRdWrPerm);
  299.     err = ResError();
  300.     nrequire(err, CouldNotOpenResourceFork);
  301.  
  302.     err = MySavePrintInfo(whichDocument, resRefNum);
  303.  
  304. // Now save the data for our document's pages.
  305.  
  306.     if (!err)
  307.         err = MySavePageCount(whichDocument, resRefNum);
  308.  
  309.     /* 
  310.         Place your application-specific code here to save 
  311.         other data associated with the document.
  312.         .
  313.         .
  314.         .
  315.     */
  316.  
  317. // Close the data and resource forks of this document.
  318.  
  319.     CloseResFile(resRefNum);
  320.  
  321. CouldNotOpenResourceFork:
  322.     FSClose(dataRefNum);
  323.  
  324. CouldNotOpenDataFork:
  325. CouldNotSetFileInfo:
  326. CouldNotDeleteOldFile:
  327. UserHasCancelled:
  328.     UseResFile(oldResFile);
  329.     return err;
  330. }
  331.  
  332.  
  333. /************************************************************
  334.   MySavePageCount - This routine saves a resource containing
  335.   the number of pages in our document.
  336.  
  337. *************************************************************/
  338.  
  339. OSErr MySavePageCount(MyDocumentPtr whichDocument, short resRefNum)
  340. {
  341.     OSErr        err;
  342.     Handle        thePageCount, oldPageCount;
  343.  
  344.     UseResFile(resRefNum);
  345.  
  346. // If there's an existing resource, delete it.
  347.  
  348.     thePageCount = NewHandle(sizeof(long));
  349.     nrequire((err = MemError()), CouldNotCreateHandle);
  350.  
  351.     *(long *)*thePageCount = whichDocument->numPages;
  352.     oldPageCount = Get1Resource(kMyPageCountType, kMyPageCountID);
  353.  
  354.     if (oldPageCount != nil)
  355.     {
  356.         RmveResource(oldPageCount);
  357.         UpdateResFile(resRefNum);
  358.         DisposHandle(oldPageCount);
  359.     }
  360.  
  361. // Add our new resource.
  362.  
  363.     AddResource(thePageCount, kMyPageCountType, kMyPageCountID, "\p");
  364.     err = ResError();
  365.     nrequire(err, CouldNotAddResource);
  366.  
  367.     WriteResource(thePageCount);
  368.     UpdateResFile(resRefNum);
  369.     ReleaseResource(thePageCount);
  370.  
  371. CouldNotAddResource:
  372. CouldNotCreateHandle:
  373.     return err;
  374. }
  375.  
  376.  
  377. /************************************************************
  378.   MyLoadPageCount - This routine loads a resource containing
  379.   the number of pages in our document, and returns the number
  380.   of pages.
  381.  
  382. *************************************************************/
  383.  
  384. long MyLoadPageCount(short resRefNum)
  385. {
  386.     Handle        thePageCount;
  387.     long        numPages;
  388.  
  389.     UseResFile(resRefNum);
  390.  
  391. // Get the page count.  If we don't find a count, return 1.
  392.  
  393.     thePageCount = Get1Resource(kMyPageCountType, kMyPageCountID);
  394.  
  395.     if (thePageCount != nil)
  396.     {
  397.         numPages = *(long *)*thePageCount;
  398.         ReleaseResource(thePageCount);
  399.     }
  400.     else
  401.         numPages = 1;
  402.  
  403.     return numPages;
  404. }
  405.  
  406.  
  407. /************************************************************
  408.   MySaveFormatRefs - This routine saves page format indices
  409.   for a document.  We'll store this info in the job's
  410.   default format's collection.  We use this information to
  411.   "reconstruct" the document the next time we open it.
  412.   This routine is called when we save a document, before we
  413.   have flattened the document's job.
  414.  
  415. *************************************************************/
  416.  
  417. OSErr MySaveFormatRefs(MyDocumentPtr whichDocument)
  418. {
  419.     OSErr                err = noErr;
  420.     Handle                theFormatIdxList;
  421.     Collection            fmtCollection;
  422.     gxFormat            defaultFmt;
  423.  
  424.     if (whichDocument->numPages > 0)
  425.     {
  426.  
  427. // Get the job's default format's collection.
  428.  
  429.         defaultFmt = GXGetJobFormat(whichDocument->documentJob, 1);
  430.         fmtCollection = GXGetFormatCollection(defaultFmt);
  431.  
  432. /*
  433.     Create a list of page-to-format correspondences for the current
  434.     document.  If there are no errors, add the item to the job's
  435.     default format's collection for later retrieval.
  436. */
  437.         err = MyCreateFormatIndexList(whichDocument, &theFormatIdxList);
  438.  
  439.         if (err == noErr)
  440.         {
  441.             HLock(theFormatIdxList);
  442.             err = AddCollectionItem(fmtCollection,
  443.                                     kMyFormatInfoType,
  444.                                     kMyFormatInfoTagID,
  445.                                     GetHandleSize(theFormatIdxList),
  446.                                     *theFormatIdxList);
  447.     
  448.             DisposHandle(theFormatIdxList);
  449.         }
  450.     }
  451.  
  452.     return err;
  453. }
  454.  
  455.  
  456. /************************************************************
  457.   MyCreateFormatIndexList - This routine stores the index of
  458.   each page's format in a handle.  The index of page #1's
  459.   format will go in the first longword of theFormatIdxList
  460.   handle, the index of the next page's format will go in
  461.   the next longword, and so on.  The handle is created and
  462.   returned to the caller.
  463.  
  464. *************************************************************/
  465.  
  466. OSErr MyCreateFormatIndexList(MyDocumentPtr whichDocument, Handle *theFormatIdxList)
  467. {
  468.     OSErr        err;
  469.     long        fmtIdx, pg, *idxList;
  470.     gxFormat    curFormat;
  471.  
  472. /*
  473.     Create a handle large enough to hold all of our entries.  We use
  474.     NewHandleClear so that all of our indices are initialized to 0
  475.     (an invalid format index).  Since our application stores a nil
  476.     format reference for any page which uses the job's default format,
  477.     this allows us to indicate these "nil references" by an index of
  478.     0 in our collection item.  When we re-open the document, we'll
  479.     know that an index of 0 means "Use the job's default format."
  480. */
  481.     *theFormatIdxList = NewHandleClear(sizeof(long) * (whichDocument->numPages));
  482.     err = MemError();
  483.  
  484. /*
  485.     If there aren't any errors, go through every format in the document's
  486.     job.  If the format is used by any pages of our document, store the
  487.     format's index in those page entries of theFormatIdxList.  We skip
  488.     format #1, since that's the job format (and we're storing nil for the
  489.     index in this case).  Because we created the handle with NewHandleClear,
  490.     nil will already be stored in any entries we don't change.
  491. */
  492.     if (err == noErr)
  493.     {
  494.         HLock(*theFormatIdxList);
  495.         idxList = (long *) **theFormatIdxList;
  496.         
  497.         for (fmtIdx = 2; fmtIdx <= GXCountJobFormats(whichDocument->documentJob); fmtIdx++)
  498.         {
  499.             curFormat = GXGetJobFormat(whichDocument->documentJob, fmtIdx);
  500.     
  501.             for (pg = 1; pg <= whichDocument->numPages; pg++)
  502.                 if (whichDocument->pageFormat[pg -1] == curFormat)
  503.                     idxList[pg -1] = fmtIdx;
  504.         }
  505.         
  506.         HUnlock(*theFormatIdxList);
  507.     }
  508.  
  509.     return err;
  510. }
  511.  
  512.  
  513. /************************************************************
  514.   MyAdjustFormats - This routine associates new format
  515.   references with a document, based upon the format indices
  516.   which were saved with the document.  The routine is called
  517.   when we open a document.
  518.   
  519.   The format references will be stored in the passed
  520.   MyDocumentPtr structure.
  521.  
  522. *************************************************************/
  523.  
  524. OSErr MyAdjustFormats(MyDocumentPtr whichDocument)
  525. {
  526.     OSErr        err = noErr;
  527.     Handle        theFormatIdxList = nil;
  528.     gxFormat    theFormat, defaultFmt;
  529.     long        pg, numPages, fmtIdx, *idxList, idx, listSize, attribs;
  530.     Collection    fmtCollection;
  531.  
  532. /*
  533.     Get the job's default format's collection, and look for one
  534.     of our page-to-format correspondence items in it.
  535. */
  536.     defaultFmt = GXGetJobFormat(whichDocument->documentJob, 1);
  537.     fmtCollection = GXGetFormatCollection(defaultFmt);
  538.  
  539. /*
  540.     Load our item containing our page-to-format correspondences.
  541.     We do this in two passes.  First we determine if the item
  542.     exists, and if so, get its size.  Next we create a handle
  543.     to hold the item (if it exists), and then actually retrieve it.
  544.     Because there will be one longword entry for each page of our
  545.     document, we can determine the number of pages in the document.
  546. */
  547.     err = GetCollectionItemInfo(fmtCollection, kMyFormatInfoType,
  548.                                 kMyFormatInfoTagID, &idx, &listSize, &attribs);
  549.  
  550.     if (err == noErr)
  551.         theFormatIdxList = NewHandle(listSize);
  552.  
  553.     if (theFormatIdxList != nil)
  554.     {
  555.         HLock(theFormatIdxList);
  556.  
  557.         err = GetCollectionItem(fmtCollection, kMyFormatInfoType,
  558.                                   kMyFormatInfoTagID, dontWantSize, *theFormatIdxList);
  559.  
  560.         numPages = listSize / sizeof(long);
  561.  
  562. /*
  563.     Now load the data for our document's pages.  (In this app, we cheat and
  564.     rebuild the pages here, rather than load and save the page data.)
  565. */
  566.         for (pg = 1; !err && (pg < numPages); pg++)
  567.         {
  568.             long    newPage = pg -1;
  569.  
  570.             err = MyInsertPage(whichDocument, &newPage);
  571.             whichDocument->curPage = pg;
  572.         }
  573.         whichDocument->curPage = 1;
  574.  
  575.     /* 
  576.         Place your application-specific code here to load 
  577.         page data associated with the document.
  578.         .
  579.         .
  580.         .
  581.     */
  582.  
  583. /*
  584.     Loop through each saved index.  The way we saved them, the first
  585.     is for page 1, the second is for page 2, and so on.  We need to call
  586.     GXGetJobFormat for each saved index.  If the index is nil, that's
  587.     just our way of saying "use the job format."  In that case, we don't
  588.     call GXGetJobFormat, we just store nil for the page's format.  Store
  589.     the format references as they're processed.  When we're done, throw
  590.     away the handle we created.
  591. */
  592.         idxList = (long *) *theFormatIdxList;
  593.         
  594.         for (pg = 0; (err == noErr) && (pg < numPages); pg++)
  595.         {
  596.             fmtIdx = idxList[pg];
  597.             
  598.             if (fmtIdx != (long) nil)
  599.             {
  600.                 theFormat = GXGetJobFormat(whichDocument->documentJob, fmtIdx);
  601.                 err = GXGetJobError(whichDocument->documentJob);
  602.             }
  603.             else
  604.                 theFormat = nil;
  605.  
  606.             if (!err)    
  607.                 whichDocument->pageFormat[pg] = theFormat;
  608.         }
  609.  
  610.         DisposHandle(theFormatIdxList);
  611.     }
  612.  
  613.     return err;
  614. }
  615.  
  616.  
  617. /************************************************************
  618.   MySavePrintInfo - This routine saves our print record or
  619.   gxJob data with the document, so that it can be used the
  620.   next time the document is opened.
  621.  
  622. *************************************************************/
  623.  
  624. OSErr MySavePrintInfo(MyDocumentPtr whichDocument, short resRefNum)
  625. {
  626.     OSErr        err;
  627.     Handle        thePrintData, oldPrintData;
  628.     OSType        dataResType;
  629.     short        dataResID;
  630.  
  631. /*
  632.     If QuickDraw GX is present, flatten the document's gxJob into a
  633.     handle so that we can write it to disk.  Otherwise, make a copy
  634.     of the document's print handle.  In either case, set up the
  635.     resource type and ID to use.  Notice how smoothly this makes
  636.     the rest of the routine work.  We don't need to worry about
  637.     whether we're storing a gxJob or a print record to disk.
  638. */
  639.  
  640.     UseResFile(resRefNum);
  641.  
  642.     if (gGXIsPresent)
  643.     {
  644.         err = MySaveFormatRefs(whichDocument);
  645.         nrequire(err, CouldNotSaveFormatRefs);
  646.  
  647.         thePrintData = NewHandle(0);
  648.         GXFlattenJobToHdl(whichDocument->documentJob, thePrintData);
  649.         err = GXGetJobError(whichDocument->documentJob);
  650.         nrequire(err, CouldNotFlattenJob);
  651.  
  652.         dataResType = kMyJobType;
  653.         dataResID = kMyJobID;
  654.     }
  655.     else
  656.     {
  657.         thePrintData = (Handle) whichDocument->documentPrintHdl;
  658.         err = HandToHand(&thePrintData);
  659.         nrequire(err, CouldNotDuplicatePrintHdl);
  660.  
  661.         dataResType = kMyPrintRecType;
  662.         dataResID = kMyPrintRecID;
  663.     }
  664.  
  665. // If there's an existing resource, delete it.
  666.  
  667.     oldPrintData = Get1Resource(dataResType, dataResID);
  668.  
  669.     if (oldPrintData != nil)
  670.     {
  671.         RmveResource(oldPrintData);
  672.         UpdateResFile(resRefNum);
  673.         DisposHandle(oldPrintData);
  674.     }
  675.  
  676. // Add our new resource.
  677.  
  678.     AddResource(thePrintData, dataResType, dataResID, "\p");
  679.     err = ResError();
  680.     nrequire(err, CouldNotAddResource);
  681.  
  682.     WriteResource(thePrintData);
  683.     UpdateResFile(resRefNum);
  684.     DetachResource(thePrintData);
  685.  
  686. CouldNotAddResource:
  687.     DisposHandle(thePrintData);
  688.  
  689. CouldNotDuplicatePrintHdl:
  690. CouldNotFlattenJob:
  691. CouldNotSaveFormatRefs:
  692.     return err;
  693. }
  694.  
  695.  
  696. /************************************************************
  697.   MyLoadPrintInfo - This routine loads our document's
  698.   previously saved print record or gxJob data.
  699.  
  700. *************************************************************/
  701.  
  702. OSErr MyLoadPrintInfo(MyDocumentPtr whichDocument, short resRefNum)
  703. {
  704.     OSErr        err = noErr;
  705.     THPrint        savedPrintHdl;
  706.     Handle        theJobData = nil;
  707.     
  708.     UseResFile(resRefNum);
  709.  
  710. /*
  711.     If we're using QuickDraw GX, and there's a job resource saved,
  712.     load it and unflatten it.  Any format references saved with a
  713.     document are no longer valid, so we need to adjust them.
  714. */
  715.     if (gGXIsPresent)
  716.     {
  717.         theJobData = Get1Resource(kMyJobType, kMyJobID);
  718.  
  719.         if (theJobData != nil)
  720.         {
  721.             GXUnflattenJobFromHdl(whichDocument->documentJob, theJobData);
  722.             err = GXGetJobError(whichDocument->documentJob);
  723.             ReleaseResource(theJobData);
  724.  
  725.             if (err == noErr)
  726.                 err = MyAdjustFormats(whichDocument);
  727.         }
  728.     }
  729.  
  730. /*
  731.     If there was no job data saved or we're not using QuickDraw GX,
  732.     try to load a previously saved print record.  If we find one,
  733.     and QuickDraw GX is being used, convert the print record to
  734.     a gxJob.  Otherwise, if we find one and QuickDraw GX is not
  735.     being used, dispose of the print handle that we allocated in
  736.     our MyCreateDocument routine.
  737.     
  738.     Note that if no gxJob or print record was previously saved,
  739.     we'll simply end up using the one we created in our
  740.     MyCreateDocument routine.  So, no matter what, we'll always
  741.     have a gxJob or print record to use!
  742. */
  743.     if (theJobData == nil)
  744.     {
  745.         savedPrintHdl = (THPrint) Get1Resource(kMyPrintRecType, kMyPrintRecID);
  746.  
  747.         if (savedPrintHdl != nil)
  748.         {
  749.             DetachResource((Handle) savedPrintHdl);
  750.  
  751.             if (gGXIsPresent)
  752.             {
  753.                 GXConvertPrintRecord(whichDocument->documentJob, savedPrintHdl);
  754.                 DisposeHandle((Handle) savedPrintHdl);
  755.                 err = GXGetJobError(whichDocument->documentJob);
  756.             }
  757.             else
  758.             {
  759.                 DisposHandle((Handle) whichDocument->documentPrintHdl);
  760.                 whichDocument->documentPrintHdl = savedPrintHdl;
  761.             }
  762.         }
  763.     }
  764.     
  765.     return err;
  766. }
  767.  
  768.  
  769.  
  770.  
  771.